package com.sgcc.pda.bluetooth.utils;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.util.Log;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 描 述：蓝牙工具类
 * 作 者：yangzhi
 * 时 间：2020/3/5 15:15
 * 版 本：1.0
 * 版 权： Copyright (c) remarkables-united.Co.Ltd. All rights reserved.
 */
public class ClsUtils {

    public static BluetoothDevice remoteDevice = null;

    /**
     * 与设备配对
     */
    static public boolean createBond(@SuppressWarnings("rawtypes") Class btClass, BluetoothDevice btDevice)
            throws Exception {
        Method createBondMethod = btClass.getMethod("createBond");
        Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice);
        return returnValue.booleanValue();
    }

    //自动配对设置Pin值
    static public boolean autoBond(Class btClass, BluetoothDevice device, String strPin) throws Exception {
        Method autoBondMethod = btClass.getMethod("setPin", new Class[]{byte[].class});
        Boolean result = (Boolean) autoBondMethod.invoke(device, new Object[]{strPin.getBytes()});
        return result;
    }

    static public void setPairingConfirmation(BluetoothDevice device) {
        try {
            Field field = device.getClass().getDeclaredField("sService");
            field.setAccessible(true);

            Object service = field.get(device);
            Method method = service.getClass().getDeclaredMethod("setPairingConfirmation",
                    BluetoothDevice.class, boolean.class);
            method.setAccessible(true);
            method.invoke(service, device, true);

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }


    /**
     * 与设备解除配对
     */
    static public boolean removeBond(Class btClass, BluetoothDevice btDevice)
            throws Exception {
        Method removeBondMethod = btClass.getMethod("removeBond");
        Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice);
        return returnValue.booleanValue();
    }

    static public boolean setPin(Class btClass, BluetoothDevice btDevice,
                                 String str) throws Exception {
        try {
            Method removeBondMethod = btClass.getDeclaredMethod("setPin",
                    new Class[]{byte[].class});
            Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice,
                    new Object[]
                            {str.getBytes()});
        } catch (SecurityException e) {
            // throw new RuntimeException(e.getMessage());
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // throw new RuntimeException(e.getMessage());
            e.printStackTrace();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return true;

    }

    // 取消用户输入
    //cancelPairingUserInput（）取消用户输入密钥框，
    // 个人觉得一般情况下不要和
    // setPin（setPasskey、setPairingConfirmation、 setRemoteOutOfBandData）一起用，
    // 这几个方法都会remove掉map里面的key:value（也就是互斥的 ）
    static public boolean cancelPairingUserInput(Class btClass,
                                                 BluetoothDevice device)

            throws Exception {
        Method createBondMethod = btClass.getMethod("cancelPairingUserInput");
        // cancelBondProcess()
        Boolean returnValue = (Boolean) createBondMethod.invoke(device);

        return returnValue.booleanValue();
    }

    // 取消配对
    static public boolean cancelBondProcess(Class btClass,
                                            BluetoothDevice device)
            throws Exception {
        Method createBondMethod = btClass.getMethod("cancelBondProcess");
        Boolean returnValue = (Boolean) createBondMethod.invoke(device);
        return returnValue.booleanValue();
    }

//    /**
//     * @param clsShow
//     */
//    @SuppressWarnings("unchecked")
//    static public void printAllInform(Class clsShow) {
//        try {
//            // 取得所有方法
//            Method[] hideMethod = clsShow.getMethods();
//            int i = 0;
//            for (; i < hideMethod.length; i++) {
//                //Log.e("method name", hideMethod.getName() + ";and the i is:"
//                //      + i);
//            }
//            // 取得所有常量
//            Field[] allFields = clsShow.getFields();
//            for (i = 0; i < allFields.length; i++) {
//                //Log.e("Field name", allFields.getName());
//            }
//        } catch (SecurityException e) {
//            // throw new RuntimeException(e.getMessage());
//            e.printStackTrace();
//        } catch (IllegalArgumentException e) {
//            // throw new RuntimeException(e.getMessage());
//            e.printStackTrace();
//        } catch (Exception e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        }
//    }

    /**
     * Clears the internal cache and forces a refresh of the services from the	 * remote device.
     */
    public static boolean refreshDeviceCache(BluetoothGatt mBluetoothGatt) {
        if (mBluetoothGatt != null) {
            try {
                BluetoothGatt localBluetoothGatt = mBluetoothGatt;
                Method localMethod = localBluetoothGatt.getClass().getMethod("refresh", new Class[0]);
                if (localMethod != null) {
                    boolean bool = ((Boolean) localMethod.invoke(localBluetoothGatt, new Object[0])).booleanValue();
                    return bool;
                }
            } catch (Exception localException) {
                Log.i("Config", "An exception occured while refreshing device");
            }
        }
        return false;
    }


    ///////////////////////////////   数据类型转换  //////////////////////////////////////////////

    /**
     * 将byte数组转化为HEX字符串
     *
     * @param value  带转化byte数组
     * @param offset 数组开始位置
     * @param length 解析长度
     * @return 转化后的字符串-正确 null-错误
     */
    public static String bytes2HexString(byte[] value, int offset, int length) {
       /*
        确保带转化数组有效
        确保传入的数组位置和长度信息没有越界
         */
        if (value == null || offset < 0 || length < 0 || offset + length > value.length) {
            return null;
        }

        StringBuilder retBuffer = new StringBuilder();

        for (int i = offset; i < offset + length; i++) {
            retBuffer.append(toHexString(value[i]));
        }

        return retBuffer.toString();
    }

    /**
     * 将byte值转化为HEX字符串
     *
     * @param value 带转化值
     * @return 转化后的HEX字符串-正确 null-错误
     */
    private static String toHexString(byte value) {
        String tmp = Integer.toHexString(value & 0xFF);
        /*
        为保证返回的字符串能够正确转化为byte数组
        保证字符串长度为2的倍数
         */
        return tmp.length() % 2 == 1 ? "0" + tmp : tmp;
    }

    /**
     * hexString2Bytes
     * 16进制字符串-->字节数组
     *
     * @param value 16进制字符串
     * @return 字节数组
     */
    public static byte[] hexString2Bytes(String value) {
        // 确保传入数据有效
        if (value == null || value.trim().length() <= 0) {
            return null;
        }
        value = value.trim();
        // 确保有效数据长度有效（为2的倍数）
        if (value.length() % 2 != 0) {
            return null;
        }

        byte[] ret = new byte[value.length() / 2];
        for (int i = 0; i < ret.length; i++) {
            try {
                /*
                前面的逻辑已经保证了字符串长度是byte数组长度的2倍
                这里没有进行数组越界的判断
                 */
                String tmp = value.substring(i * 2, i * 2 + 2);
                int a = Integer.parseInt(tmp, 16);
                int b = a & 0xFF;
                byte c = (byte) b;
                ret[i] = (byte) (Integer.parseInt(tmp, 16) & 0xFF);
            } catch (Exception e) {
                return null;
            }
        }
        return ret;
    }

}
